#pragma once
#include <vector>
#include <queue>
#include <pthread.h>
#include <unistd.h>
#include <functional>
#include "lockguard.hpp"
#include "thread.hpp"
#include "../common/nocopy.hpp"

const int THREAD_NUM = 3;
using threadcb_func = function<void(void *)>;

template <class D>
class ThreadPool : public NoCopy
{
    int _thread_num;
    std::vector<MyThread> _threads;
    std::queue<D> _datas;
    static pthread_mutex_t _mtx;
    static pthread_cond_t _cond;
    bool _terminate = false; // 结束标志

    struct ThreadData //线程入口函数参数
    {
        threadcb_func _task;
        ThreadPool *_threadpool; // 可以为空，表示自主获取
        bool _active;
        ThreadData(threadcb_func task, ThreadPool *resource, bool active = false)
            : _task(task),
              _resource(resource),
              _active(active)
        {
        }
    };

    std::shared_ptr<ThreadData> _threadData;

public:
    ThreadPool(threadcb_func task, bool active = false, int thread_num = THREAD_NUM)
        : _thread_num(thread_num),
          _threads(_thread_num)
    {
        _threadData = std::make_shared<ThreadData>(task, this, active)
    }

    ~ThreadPool()
    {
        _terminate = true;              // 设置结束标志
        pthread_cond_broadcast(&_cond); // 唤醒所有等待条件变量的线程
        for (auto &e : _threads)        // 回收所有子线程
        {
            e.join();
        }
    }

    void push(const D &data)
    {
        LockGuard lock(_mtx);
        _datas.push(data);
        pthread_cond_signal(&_cond);
    }

    bool pop(D &data)
    {
        LockGuard lock(_mtx); // 有阻塞的问题
        while (_datas.empty())
        {
            pthread_cond_wait(&_cond, &_mtx);
            if (_terminate)
                return false;
        }
        data = _datas.front();
        _datas.pop();
        return true;
    }

    void run()
    {
        for (auto &e : _threads)
        {
            e.run(routine, _threadData.get());
        }
    }
    // pthread_creat函数要求的线程入口点函数的参数只有一个void*，不能有this指针。
    static void *routine(void *args)
    {
        ThreadData *td = (ThreadData *)args; // self实际就是this指针
        if (!td->_active)
        {
            D data;
            while (!td->_threadpool->_terminate) // 被动投喂数据
            {
                bool ret = self->pop(&data);
                if (ret) // 判断self->pop是否获取到数据
                {
                    td->_task(&data);
                }
            }
        }
        else
        {
            _task(&td->_threadpool->_terminate); // 主动获取数据（也是一个循环体）
        }

        return (void *)0;
    }
};
template <class T>
pthread_mutex_t ThreadPool<T>::_mtx = PTHREAD_MUTEX_INITIALIZER;
template <class T>
pthread_cond_t ThreadPool<T>::_cond = PTHREAD_COND_INITIALIZER;
